#ifdef WWWPAL
#include "HTRobMan.h"
#include "XGMML_DTD.h"
#include "XGMMLGen.h"

#define XML_STRING "<?xml version=\"1.0\"?>\n"
#define DOCTYPE_STRING "<!DOCTYPE graph PUBLIC \"-//John Punin//DTD graph description//EN\" \"http://www.cs.rpi.edu/~puninj/XGMML/xgmml.dtd\">\n"

#define PUT_CHAR(c)	(*me->target->isa->put_character)(me->target, c)
#define PUT_STR(s)	(*me->target->isa->put_string)(me->target, s)
#define PUT_BLOCK(s,l)	(*me->target->isa->put_block)(me->target, s, l)

#define BUFFER_SIZE	80	/* Line buffer attempts to make neat breaks */

/* XGMML Generator Object */
struct _HTStream {
    const HTStreamClass *	isa;
    HTStream *			target;
};

struct _HTStructured {
    const HTStructuredClass *	isa;
    HTStream * 			target;
    const SGML_dtd *		dtd;
    char			buffer[BUFFER_SIZE+1];
    char *			write_pointer;
};


PRIVATE int XGMMLGen_flush (HTStructured * me)
{ 
    PUT_BLOCK(me->buffer, me->write_pointer - me->buffer);
    me->write_pointer = me->buffer;
    return HT_OK;
}

PRIVATE int XGMMLGen_output_character (HTStructured * me, char c)
{
    *me->write_pointer++ = c;
    if (me->write_pointer >= me->buffer + BUFFER_SIZE-1) {
	XGMMLGen_flush (me);
    }
    return HT_OK;
}


/*	String handling
**	---------------
*/
PRIVATE int XGMMLGen_output_string (HTStructured * me, const char* s)
{
    while (*s)
	XGMMLGen_output_character(me, *s++);
    return HT_OK;
}

PRIVATE int XGMMLGen_put_character (HTStructured * me, char c)
{
    if (c=='&') XGMMLGen_output_string(me, "&amp;");
    else if (c=='<') XGMMLGen_output_string(me, "&lt;");
    else if (c=='>') XGMMLGen_output_string(me, "&gt;");
    else if (c=='\"') XGMMLGen_output_string(me, "&quot;"); /* " */
    else if (c=='\'') XGMMLGen_output_string(me, "&apos;");
    else
	XGMMLGen_output_character(me, c);
    return HT_OK;
}

PRIVATE int XGMMLGen_put_string (HTStructured * me, const char* s)
{
    while (*s)
	XGMMLGen_put_character(me, *s++);
    return HT_OK;
}

PRIVATE int XGMMLGen_write (HTStructured * me, const char* b, int l)
{
    while (l-- > 0)
	XGMMLGen_put_character(me, *b++);
    return HT_OK;
}

PRIVATE void XGMMLGen_start_element (
	HTStructured * 	me,
	int			element_number,
	const BOOL*	 	present,
	const char **		value)
{
    int i;
    HTTag * tag = &me->dtd->tags[element_number];

    XGMMLGen_output_character(me, '<');
    XGMMLGen_output_string(me, tag->name);
    if (present) for (i=0; i< tag->number_of_attributes; i++) {
        if (present[i]) {
	    XGMMLGen_output_character(me, ' ');
	    XGMMLGen_output_string(me, tag->attributes[i].name);
	    if (value[i]) {
	 	XGMMLGen_output_string(me, "=\"");
		XGMMLGen_put_string(me, value[i]);
		XGMMLGen_output_character(me, '"');
	    }
	}
    }
    if(tag->contents == SGML_EMPTY)
	XGMMLGen_output_string(me, "/>\n");
    else
	XGMMLGen_output_string(me, ">\n");
}

PRIVATE void XGMMLGen_end_element (HTStructured * me, int element_number)
{
    HTTag * tag = &me->dtd->tags[element_number];
    if(tag->contents != SGML_EMPTY) {
	XGMMLGen_output_string(me, "</");
	XGMMLGen_output_string(me,tag->name);
	XGMMLGen_output_string(me, ">\n");	   
    }
}

PRIVATE void XGMMLGen_put_entity (HTStructured * me, int entity_number)
{
    XGMMLGen_output_character(me, '&');
    XGMMLGen_output_string(me, me->dtd->entity_names[entity_number]);
    XGMMLGen_output_character(me, ';');
}

PRIVATE int XGMMLGen_free (HTStructured * me)
{
    XGMMLGen_flush(me);
    PUT_CHAR('\n');
    (*me->target->isa->_free)(me->target);
    HT_FREE(me);
    return HT_OK;
}


PRIVATE int XGMMLGen_abort (HTStructured * me, HTList * e)
{
    XGMMLGen_free(me);
    return HT_ERROR;
}



/*	Structured Object Class
**	-----------------------
*/
PRIVATE const HTStructuredClass XGMMLGeneration = /* As opposed to print etc */
{		
	"text/xgmml",
	XGMMLGen_flush,
	XGMMLGen_free,
	XGMMLGen_abort,
	XGMMLGen_put_character, 	XGMMLGen_put_string, XGMMLGen_write,
	XGMMLGen_start_element,	XGMMLGen_end_element,
	XGMMLGen_put_entity,
	NULL, NULL, NULL
}; 

/*	Subclass-specific Methods
**	-------------------------
*/
PUBLIC HTStructured* XGMMLGenerator (HTRequest *	request,
				    void *	param,
				    HTFormat	input_format,
				    HTFormat	output_format,
				    HTStream *	output_stream)
{
    HTStructured* me;
    if ((me = (HTStructured  *) HT_CALLOC(1, sizeof(HTStructured))) == NULL)
        HT_OUTOFMEM("XGMMLGenerator");
    me->isa = &XGMMLGeneration;       
    me->dtd = XGMML_dtd();
    /*me->target = output_stream;*/
    if((me->target = HTStreamStack(input_format, output_format, output_stream,
				   request, YES)) == NULL) {
	if (STREAM_TRACE)
	    HTTrace("XGMMLGen..... Can't convert to media type\n");
	HT_FREE(me);
	me->target = HTErrorStream();
    }
    me->write_pointer = me->buffer;
    XGMMLGen_output_string(me,XML_STRING);
    XGMMLGen_output_string(me,DOCTYPE_STRING);
    return me;
}

#endif





